<h1 id="modules">Modules</h1>

<h2>Overview</h2>

<p>Duktape has a built-in minimal module loading framework based on
<a href="http://wiki.commonjs.org/wiki/Modules/1.1.1">CommonJS modules version 1.1.1</a>.
The internals are documented in
<a href="https://github.com/svaarala/duktape/blob/master/doc/modules.rst">modules.rst</a>.
A recommended (but not mandatory) C module convention is described in
<a href="https://github.com/svaarala/duktape/blob/master/doc/c-module-convention.rst">c-module-convention.rst</a>.
</p>

<p>You can load modules from Ecmascript code with the global <code>require()</code> function:</p>
<pre class="ecmascript-code">
var mod = require('foo/bar');
mod.hello();
</pre>

<p>Modules are defined by Ecmascript code running in a special environment
defined by the CommonJS modules specification.  Inside this environment,
variable/function declarations are local to the module and don't affect the
global object.  The environment also provides three special symbols related
to module loading: <code>exports</code> for exporting module symbols,
<code>module</code> for providing module metadata (<code>module.id</code>
in particular), and <code>require()</code> for loading further modules with
relative module identifiers resolved in the context of the current module.
Example:</p>
<pre class="ecmascript-code">
// foo/bar.js
var text = 'Hello world!';     // not visible outside the module
var quux = require('./quux');  // loads foo/quux
exports.hello = function () {
    print(text);
};
</pre>

<p>Because Duktape is embeddable and portable to different environments there
is no standard way to search for modules.  <b>User code must provide a module
search function</b> in <code>Duktape.modSearch</code> for module loading to work.
The module search function essentially maps a module identifier to the source
code of the module (see below for more details).  Example:</p>
<pre class="ecmascript-code">
// See module search function details below.
Duktape.modSearch = function (id) {
    print('loading module:', id);
    // Return source code for module or throw an error.
};
</pre>

<h2>Module search function</h2>

<p>The module search function encapsulates all platform specific concerns,
such as module search paths and file system access, related to finding a
module matching a certain identifier:</p>
<pre class="ecmascript-code">
Duktape.modSearch = function (id, require, exports, module) {
    // ...
};
</pre>

<p>The arguments of the module search function are:</p>
<ul>
<li>A fully resolved module ID.  Relative IDs are converted to absolute
    IDs and there are no unresolved <code>.</code> or <code>..</code>
    ID terms.</li>
<li>A <code>require()</code> function for loading further modules.
    Relative module IDs are resolved relative to the current module.
    For instance, if <code>foo/bar</code> is being loaded, the
    <code>require()</code> function given to the module search function
    would resolve <code>./quux</code> to <code>foo/quux</code>.</li>
<li>A <code>exports</code> object to export symbols during module search.
    Writing to exports within the module search function is only needed
    when loading native (Duktape/C) modules.</li>
<li>A <code>module</code> object which provides metadata about the module
    being loaded.  The only property provided now is <code>module.id</code>,
    a resolved absolute identifier for the module being loaded.</li>
</ul>

<p>If a module is not found, the module search function is expected to throw
an error.  This error will propagate out to the code which originally called
<code>require()</code> so it should have a useful error message containing the
module identifier.  Any changes made to <code>exports</code> before throwing
the error are thrown away.</p>

<p>If a module is found, the module search function can return a string
providing the source code for the module.  Duktape will then take care of
compiling and executing the module code so that module symbols get registered
into the <code>exports</code> object.</p>

<p>The module search function can also add symbols directly to the
<code>exports</code> object.  This can be used to implement native (Duktape/C)
modules and platform specific DLL loading support.  For example, the module
search function could call a native module initializer (provided by a DLL)
which registered all the native functions and constants into the
<code>exports</code> object.</p>

<p>To support the native module case, the module search function can also
return <code>undefined</code> (or any non-string value), in which case
Duktape will assume that the module was found but has no Ecmascript source
to execute.  Symbols written to <code>exports</code> in the module search
function are the only symbols provided by the module.</p>

<p>Hybrid modules containing both C and Ecmascript code are also supported:
simply write native symbols into the <code>exports</code> table inside the
module search function, and return the module's Ecmascript code.  Duktape
will then execute the Ecmascript code, which can access symbols already
registered into the <code>exports</code> table and register further symbols.</p>

<p>The module search function can be either an Ecmascript function or a
Duktape/C function.</p>

<h2>Implementing a module search function</h2>

<p>Here's a simply module search stub which provides two modules:</p>
<pre class="ecmascript-code">
Duktape.modSearch = function (id) {
    if (id === 'foo') {
        return 'exports.hello = function() { print("Hello from foo!"); };';
    } else if (id === 'bar') {
        return 'exports.hello = function() { print("Hello from bar!"); };';
    }
    throw new Error('module not found: ' + id);
};
</pre>

<p>A more practical module search function is almost always platform dependent
because modules are most often loaded from disk.  Usually a Duktape/C binding
is needed to access the file system.  The example below loads modules using a
hypothetical <code>readFile</code> function:</p>
<pre class="ecmascript-code">
Duktape.modSearch = function (id) {
    /* readFile() reads a file from disk, and returns a string or undefined.
     * 'id' is in resolved canonical form so it only contains terms and
     * slashes, and no '.' or '..' terms.
     */
    var res;

    print('loading module:', id);

    res = readFile('/modules/' + id + '.js');
    if (typeof res === 'string') {
        return res;
    }

    throw new Error('module not found: ' + id);
}
</pre>

<p>The following module search function supports pure C, pure Ecmascript, and
mixed modules.  C modules are loaded and initialized with a hypothetical
<code>loadAndInitDll</code> function which loads a DLL, and if found, calls an
init function so that the DLL initializer can register exported symbols:</p>
<pre class="ecmascript-code">
Duktape.modSearch = function (id, require, exports, module) {
    /* readFile(): as above.
     * loadAndInitDll(): load DLL, call its init function, return true/false.
     */
    var name;
    var src;
    var found = false;

    print('loading module:', id);

    /* DLL check.  DLL init function is platform specific.  It gets 'exports'
     * but also 'require' so that it can require further modules if necessary.
     */
    name = '/modules/' + id + '.so';
    if (loadAndInitDll(name, require, exports, module)) {
        print('loaded DLL:', name);
        found = true;
    }

    /* Ecmascript check. */
    name = '/modules/' + id + '.js';
    src = readFile(name);
    if (typeof src === 'string') {
        print('loaded Ecmascript:', name);
        found = true;
    }

    /* Must find either a DLL or an Ecmascript file (or both) */
    if (!found) {
        throw new Error('module not found: ' + id);
    }

    /* For pure C modules, 'src' may be undefined which is OK. */
    return src;
}
</pre>

<p>The module search function could also load modules from a compressed
in-memory store, or load the modules over the network.  However, a module
search function cannot do a coroutine yield, so network access will block the
application; it is most useful for testing.</p>

<!-- XXX: this is just a placeholder, perhaps a separate guide section or integrate
     better with text elsewhere in this section.
-->
<h2 id="writing-c-modules">Writing modules in C</h2>

<p>There's a recommended (but not mandatory) convention for writing C modules, see
<a href="https://github.com/svaarala/duktape/blob/master/doc/c-module-convention.rst">c-module-convention.rst</a>.</p>

<p>Most C modules will need the following parts:</p>
<pre class="c-code">
/*
 *  Identify module
 */

/* Include duktape.h and whatever platform headers are needed. */
#include "duktape.h"

/*
 *  Duktape/C functions providing module functionality.
 */

static duk_ret_t my_func_1(duk_context *ctx) {
    /* ... */
}

static duk_ret_t my_func_2(duk_context *ctx) {
    /* ... */
}

/* ... */

/*
 *  Module initialization
 */

static const duk_function_list_entry my_module_funcs[] = {
    { "func1", my_func_1, 3 /*nargs*/ },
    { "func2", my_func_2, DUK_VARARGS /*nargs*/ },
    { NULL, NULL, 0 }
};

static const duk_number_list_entry my_module_consts[] = {
    { "FLAG_FOO", (double) (1 &lt;&lt; 0) },
    { NULL, 0.0 }
};

/* Init function name is dukopen_&lt;modname&gt;. */
duk_ret_t dukopen_my_module(duk_context *ctx) {
    duk_push_object(ctx);
    duk_put_function_list(ctx, -1, my_module_funcs);
    duk_put_number_list(ctx, -1, my_module_consts);

    /* Return value is the module object.  It's up to the caller to decide
     * how to use the value, e.g. write to global object.
     */
    return 1;
}
</pre>

<p>The calling application which wants to load this module manually (outside
of CommonJS module loading) will then simply:</p>
<pre class="c-code">
int main(int argc, char *argv[]) {
    duk_context *ctx;

    ctx = duk_create_heap_default(ctx);
    if (!ctx) {
        /* ... */
    }

    /* Module loading happens with a Duktape/C call wrapper. */
    duk_push_c_function(ctx, dukopen_my_module, 0 /*nargs*/);
    duk_call(ctx, 0);
    duk_put_global_string(ctx, "my_module");

    /* my_module is now registered in the global object. */
    duk_eval_string_noresult(ctx, "my_module.func2()");

    /* ... */

    duk_destroy_heap(ctx);
    return 0;
}
</pre>

<p>C modules can also be loaded using a CommonJS module loader, in which case
the module loader would call the init function (e.g. located from a DLL).</p>

<h2>Limitations</h2>

<ul>
<li>Duktape does not support <code>module.exports</code>.  This also means that
    the return value from <code>require()</code> is always an object, and cannot
    be e.g. a constructor function.</li>
<li>When implementing native modules in the module search function, circular
    module references are not supported because the module's <code>exports</code>
    table is not registered by Duktape as a "module being loaded" before the
    module search function exits.  Circular module references are supported for
    pure Ecmascript modules.</li>
</ul>
